package com.ming.filter;

import com.ming.pojo.vo.Result;
import com.ming.util.JwtUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.ArrayList;

/**
 * JWT认证过滤器
 * 在Spring Security框架内处理JWT认证
 *
 * @author ming
 * @version 1.0
 */
@Slf4j
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        try {
            // 获取请求路径
            String requestURI = request.getRequestURI();
            String method = request.getMethod();
            log.info("JWT过滤器处理请求: {} {}", method, requestURI);

            // 对于OPTIONS请求直接放行
            if ("OPTIONS".equals(method)) {
                filterChain.doFilter(request, response);
                return;
            }

            // 检查是否为无需token验证的接口
            if (isPublicEndpoint(requestURI, method)) {
                log.info("公开接口，跳过token验证: {} {}", method, requestURI);
                filterChain.doFilter(request, response);
                return;
            }

            // 获取token
            String token = getTokenFromRequest(request);

            if (token == null) {
                log.info("未找到token，继续Spring Security处理: {}", requestURI);
                // 没有token时放行请求，让Spring Security决定是否需要认证
                filterChain.doFilter(request, response);
                return;
            }

            // 验证token
            if (!jwtUtils.validateToken(token)) {
                log.warn("token验证失败，请求路径: {}", requestURI);
                sendUnauthorizedResponse(response, "token无效或已过期，请重新登录");
                return;
            }

            // 获取用户信息
            Integer userId = jwtUtils.getUserIdFromToken(token);
            String username = jwtUtils.getUsernameFromToken(token);
            String name = jwtUtils.getNameFromToken(token);

            log.info("JWT验证成功，用户: {} (ID: {})", username, userId);

            // 创建认证对象并设置到SecurityContext
            UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

            // 将用户信息设置到认证对象的principal中
            authentication.setDetails(userId); // 设置用户ID

            SecurityContextHolder.getContext().setAuthentication(authentication);

            filterChain.doFilter(request, response);

        } catch (Exception e) {
            log.error("JWT过滤器处理异常", e);
            sendUnauthorizedResponse(response, "token解析异常，请重新登录");
        }
    }

    
    /**
     * 从请求中获取token
     */
    private String getTokenFromRequest(HttpServletRequest request) {
        // 1. 从Authorization头中获取（推荐方式）
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            // 过滤无效的token值
            if (isValidToken(token)) {
                return token;
            }
        }

        // 2. 从token参数中获取（兼容方式）
        String tokenParam = request.getParameter("token");
        if (tokenParam != null && !tokenParam.trim().isEmpty() && isValidToken(tokenParam)) {
            return tokenParam;
        }

        return null;
    }

    /**
     * 检查是否为公开接口（无需token验证）
     */
    private boolean isPublicEndpoint(String requestURI, String method) {
        // 登录接口
        if (requestURI.equals("/emps/login") && "POST".equals(method)) {
            return true;
        }

        // 错误页面
        if (requestURI.equals("/error")) {
            return true;
        }

        // 健康检查
        if (requestURI.startsWith("/actuator/")) {
            return true;
        }

        // Swagger相关
        if (requestURI.startsWith("/swagger-ui/") ||
            requestURI.startsWith("/v3/api-docs/") ||
            requestURI.startsWith("/swagger-resources/") ||
            requestURI.startsWith("/webjars/")) {
            return true;
        }

        // 文件访问
        if (requestURI.startsWith("/files/")) {
            return true;
        }

        return false;
    }

    /**
     * 检查token值是否有效（排除无效值如"undefined"、"null"等）
     */
    private boolean isValidToken(String token) {
        return token != null &&
               !token.trim().isEmpty() &&
               !"undefined".equalsIgnoreCase(token) &&
               !"null".equalsIgnoreCase(token) &&
               !token.equals("{{token}}") && // 处理模板变量未替换的情况
               token.length() > 10; // JWT token通常比较长
    }

    /**
     * 发送未授权响应
     */
    private void sendUnauthorizedResponse(HttpServletResponse response, String message) throws IOException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");

        Result result = Result.error(message);
        String jsonResult = objectMapper.writeValueAsString(result);

        try (var writer = response.getWriter()) {
            writer.write(jsonResult);
            writer.flush();
        }
    }
}